package com.lcz.ssm.utils;

import com.lcz.ssm.exception.AppException;
import com.lcz.ssm.model.BaseVO;
import net.rubyeye.xmemcached.MemcachedClient;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.io.IOUtils;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;

/**
 * Unibon
 * <p/>
 * Copyright (c) 2012 YouPeng ValueSoft Inc., All rights reserved.
 * <p/>
 * This software is the confidential and proprietary information of
 * ValueSoft Company. ("Confidential Information").  You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with ValueSoft.com.
 * <p/>
 * Revision History
 * Date      		Programmer       Notes
 * 2014/5/13   	     libo		     Initial
 * *********************************************************************
 */
public class AjaxResponse {
    private ModelAndView mav = new ModelAndView();
    private HttpServletRequest request;
    private MemcachedClient memcachedClient;
    private String jsonPath;
    private List<Map<String, Object>> errors = new ArrayList<Map<String, Object>>();
    private String dateFormat = "yyyy-MM-dd HH:mm:ss";
    private Boolean silent = false;
    private String successMsg = "";

    public AjaxResponse(HttpServletRequest request, MemcachedClient memcachedClient,
                        String jsonPath) {

        mav.addObject("stat", ResponseEnum.OK);
        mav.addObject("silent",silent );
        mav.addObject("successMsg",successMsg );
        mav.addObject("data", new JSONObject());
        mav.addObject("errors", errors);
        this.request = request;
        this.memcachedClient = memcachedClient;
        this.jsonPath = jsonPath;
    }

    /**
     * 添加集合
     *
     * @param coll
     */
    public void addCollection(Object coll) {
        JSONObject data = getData();
        data.put("collection", coll);
    }


    /**
     * successMsg
     *
     * @param successMsg
     */
    public void setSuccessMsg(String successMsg) {
        mav.addObject("successMsg", successMsg);
    }

    /**
     * silent
     *
     * @param silent
     */
    public void setSilent(Boolean silent) {
        mav.addObject("silent", silent);
    }

    public ModelMap getModelMap() {
        return this.mav.getModelMap();
    }

    /**
     * 添加模型
     *
     * @param model
     */
    public void addModel(Object model) {
        JSONObject data = getData();
        JSONObject modelStru = getModelStru();
        if (modelStru == null) {
            data.put("model", model);
        } else {
            JSONObject jsonObject = filterModel(model, modelStru);
            data.put("model", jsonObject);
        }
    }


    /**
     * 添加模型无stru
     *
     * @param model
     */
    public void addModelObject(Object model) {
        JSONObject data = getData();
        data.put("model", model);
    }


    public void addModels(List model) {
        JSONObject modelStru = getModelStru();
        if (modelStru == null) {
            addCollection(model);
        } else {
            JSONArray array = new JSONArray();
            if (model != null) {
                for (Object result : model) {
                    JSONObject jsonObject = filterModel(result, modelStru);
                    array.add(jsonObject);
                }
            }
            addCollection(array);
        }
    }

    public void addObject(String key, Object value) {
        JSONObject data = getData();
        data.put(key, value);
    }

    public void setStat(ResponseEnum respEnum) {
        mav.addObject("stat", respEnum);
    }

    /**
     * 添加分页信息
     *
     * @param page
     */
    public void addPagination(Pagination page) {
        JSONObject data = getData();
        data.put("currentPage", page.getCurrentPage());
        data.put("totalPages", page.getTotalPages());
        data.put("totalCount", page.getCount());

        List<?> results = page.getResults();
        JSONObject modelStru = getModelStru();
        if (modelStru == null) {
            addCollection(results);
        } else {
            JSONArray array = new JSONArray();
            if (results != null) {
                for (Object result : results) {
                    JSONObject jsonObject = filterModel(result, modelStru);
                    array.add(jsonObject);
                }
            }
            addCollection(array);
        }
    }

    /**
     * 添加错误信息
     *
     * @param msg
     */
    public void addError(String msg) {
        mav.addObject("stat", ResponseEnum.ERROR);
        Map<String, Object> error = new HashMap<String, Object>();
        error.put("field", "error");
        error.put("msg", msg);
        errors.add(error);
    }

    public void addError(BindingResult br) {
        mav.addObject("stat", ResponseEnum.VERIFY_FAIL);
        for (ObjectError objectError : br.getAllErrors()) {
            Map<String, Object> error = new HashMap<String, Object>();
            error.put("field", ((FieldError) objectError).getField());
            error.put("msg", objectError.getDefaultMessage());
            errors.add(error);
        }
    }

    /**
     * 验证错误
     *
     * @param field
     * @param failCode
     * @return
     */
    public void addError(String field, String failCode) {
        mav.addObject("stat", ResponseEnum.VERIFY_FAIL);
        Map<String, Object> error = new HashMap<String, Object>();
        error.put("field", field);
        String message = ValidationMessage.getMessage(failCode);
        if (message == null) {
            error.put("msg", failCode);
        } else {
            error.put("msg", ValidationMessage.getMessage(failCode));
        }
        errors.add(error);
    }


    public void addErrorShow(String field, String failCode) {
        mav.addObject("stat", ResponseEnum.ERROR);
        Map<String, Object> error = new HashMap<String, Object>();
        error.put("field", field);
        String message = ValidationMessage.getMessage(failCode);
        if (message == null) {
            error.put("msg", failCode);
        } else {
            error.put("msg", ValidationMessage.getMessage(failCode));
        }
        errors.add(error);
    }




    public JSONObject getData() {
        return (JSONObject) mav.getModelMap().get("data");
    }

    public ModelAndView getMav() {
        return mav;
    }

    /**
     * 取得模型返回结构
     *
     * @return
     */
    private JSONObject getModelStru() {
        String url = buildUrl();
        JSONObject modelStru = null;

        if(memcachedClient==null){
            return null;
        }
        try {
            modelStru = this.memcachedClient.get(url);
        } catch (Exception e) {
            modelStru = null;
        }
        try {
            if ((modelStru == null && !this.jsonPath.equals("")) || true) {
                InputStreamReader inputStreamReader = new InputStreamReader(this.getClass().getResourceAsStream(this.jsonPath), "UTF-8");
                String jsonTxt = IOUtils.toString(inputStreamReader);
                JSONObject obj = JSONObject.fromObject(jsonTxt);
                modelStru = (JSONObject) obj.get(url);
                if (modelStru != null) {
                    this.memcachedClient.set(url, 0, modelStru);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }

        return modelStru;
    }

    private JSONObject filterModel(Object model, JSONObject modelStru) {
        JSONObject jsonObject = new JSONObject();
        Iterator<Map.Entry<String, JSONObject>> iterator = modelStru.entrySet().iterator();
        Map<String, Field> fieldMap = getField(model.getClass());
        while (iterator.hasNext()) {
            Map.Entry<String, JSONObject> next = iterator.next();
            String key = next.getKey();
            try {
                if (model instanceof Map) {
                    if (((Map) model).containsKey(key)) {
                        Object mapObj = ((Map) model).get(key);
                        if (mapObj == null) {
                            jsonObject.put(key, mapObj);
                        } else {
                            if (List.class.isAssignableFrom(mapObj.getClass())) {
                                List list = (List) mapObj;
                                JSONObject value = next.getValue();
                                JSONArray array = new JSONArray();
                                for (Object obj : list) {
                                    JSONObject jsonObj = filterModel(obj, value);
                                    array.add(jsonObj);
                                }
                                jsonObject.put(key, array);
                            } else if (Date.class.isAssignableFrom(mapObj.getClass())) {
                                Date date = (Date) mapObj;
                                jsonObject.put(key, DateUtil.dateToString(date, dateFormat));
                            } else if (Map.class.isAssignableFrom(mapObj.getClass())) {
                                jsonObject.put(key, JSONObject.fromObject(mapObj));
                            } else {
                                jsonObject.put(key, mapObj);
                            }
                        }
                    }
                } else {
                    Field field = fieldMap.get(key);
                    if (field != null) {
                        field.setAccessible(true);
                        Class typeClass = field.getType();
                        if (typeClass.equals(Short.class)
                                || typeClass.equals(Boolean.class) || typeClass.equals(String.class)
                                || typeClass.equals(Double.class) || typeClass.equals(Integer.class)
                                || typeClass.equals(Long.class) || typeClass.equals(BigDecimal.class)||typeClass.equals(boolean.class)) {
                            jsonObject.put(key, field.get(model));
                        } else if (typeClass.equals(Date.class)) {
                            Date date = (Date) field.get(model);
                            jsonObject.put(key, DateUtil.dateToString(date, dateFormat));
                        } else if (typeClass.equals(List.class)) {
                            JSONObject value = next.getValue();
                            List list = (List) field.get(model);
                            JSONArray array = new JSONArray();
                            if(list != null) {
                                for (Object obj : list) {
                                    JSONObject jsonObj = filterModel(obj, value);
                                    array.add(jsonObj);
                                }
                            }
                            jsonObject.put(key, array);
                        }
                        else if (BaseVO.class.isAssignableFrom(typeClass)) {
                            JSONObject value = next.getValue();
                            Object obj = field.get(model);
                            if (obj != null) {
                                JSONObject jsonObj = filterModel(obj, value);
                                jsonObject.put(key, jsonObj);
                            }
                        }
                        else {
                            throw new AppException(key + " Type not defined");
                        }
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return jsonObject;
    }

    private Map<String, Field> getField(Class _class) {
        Map<String, Field> fieldMap = new HashMap<String, Field>();
        Field[] fields = _class.getDeclaredFields();
        for (Field field : fields) {
            fieldMap.put(field.getName(), field);
        }
        if (_class.getSuperclass() != null) {
            Map<String, Field> superFieldMap = getField(_class.getSuperclass());
            fieldMap.putAll(superFieldMap);
        }
        return fieldMap;
    }

    /**
     * 取得请求路径和方法
     *
     * @return
     */
    public String buildUrl() {
        String path = request.getRequestURI();
        String contextPath = request.getContextPath();
        path = path.replace(contextPath, "");
        StringBuffer sb = new StringBuffer();

        //过滤请求后缀如.json .xml等
        if (path.indexOf(".") != -1) {
            path = path.split("\\.")[0];
        }
        //过滤数字
        String[] pathArray = path.split("/");
        for (String p : pathArray) {
            if (!org.apache.commons.lang.StringUtils.isBlank(p)) {
                sb.append("/");
                if (RegExpUtil.isNumeric(p)) {//isNumeric
                    sb.append("*");
                }else if(p.length() > 30 || p.contains("-")){//长度大于30(链接中的字符一般不会超过30)
                    sb.append("*");
                } else {
                    sb.append(p);
                }
            }
        }
        String method = request.getMethod();
        String _method = request.getParameter("_method");
        sb.append(":");
        if (!org.apache.commons.lang.StringUtils.isBlank(_method)) {
            sb.append(_method.toLowerCase());
        } else {
            sb.append(method.toLowerCase());
        }
        return sb.toString();
    }

    public String getDateFormat() {
        return dateFormat;
    }

    public void setDateFormat(String dateFormat) {
        this.dateFormat = dateFormat;
    }


}
